#include <AppModel/Include/Semaphore.h>

Semaphore::Semaphore(unsigned int valor_inicial)
{
    this->semaphore_handle = CreateSemaphore(NULL, valor_inicial, MAX_SEMAPHORE_VALUE, NULL);
    this->semaphore_deleted = false;
}

Semaphore::~Semaphore(void)
{
    this->semaphore_deleted = true;
    ReleaseSemaphore(this->semaphore_handle, MAX_SEMAPHORE_VALUE, NULL);
    CloseHandle(this->semaphore_handle);
}

void Semaphore::signal()
{
    ReleaseSemaphore(this->semaphore_handle, 1, NULL);
}

void Semaphore::wait(unsigned int _timeout)
{
    DWORD timeout = INFINITE;
    if (_timeout != 0)
    {
        timeout = _timeout;
    }

    DWORD r = WaitForSingleObject(this->semaphore_handle, timeout);
    
    if (this->semaphore_deleted)
    {
        throw SemaphoreExceptionType::SEMAPHORE_DELETED_EXCEPTION;
    }
    if (r == WAIT_TIMEOUT)
    {
        throw SemaphoreExceptionType::SEMAPHORE_TIMEOUT_EXCEPTION;
    }
}

void Semaphore::reset()
{
    DWORD r = 0;
    while ( r != WAIT_TIMEOUT )
    {
        r = WaitForSingleObject(this->semaphore_handle, 0);
        // when it returns because of timeout, it is reseted
        // it returns with r == 0, if it is signaled.        
    }
}
